# -*- coding: utf-8 -*-
# @File: main_linux_spider.py
# Author: Chimengmeng
# Blog URL: https://www.cnblogs.com/dream-ze/
# Time: 2023/9/2
from CommonMatplotlib import CommonMatplot
import paramiko
import re
from linux_info import settings
import redis


class RemoteServerMonitor:
    def __init__(self, host=settings.HOST, port=settings.PORT,
                 username=settings.USERNAME, password=settings.PASSWORD):
        # 服务器IP地址
        self.host = host
        # 服务器IP端口
        self.port = port
        # 服务器 用户名
        self.username = username
        # 服务器 密码
        self.password = password
        # 初始化链接对象
        self.ssh_client = paramiko.SSHClient()
        # 创建SSH客户端
        self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        # 调用链接函数进行初始化链接
        self.connect()

    def connect(self):
        try:
            # 建立SSH连接
            self.ssh_client.connect(self.host, self.port, username=self.username, password=self.password)
        except paramiko.AuthenticationException:
            raise Exception("认证失败，请检查您的凭据。")
        except paramiko.SSHException as e:
            raise Exception(f"SSH连接失败：{str(e)}")
        except Exception as e:
            raise Exception(f"错误：{str(e)}")

    def execute_command(self, command):
        try:
            # 执行远程命令
            stdin, stdout, stderr = self.ssh_client.exec_command(command)
            return stdout.read().decode('utf-8')
        except Exception as e:
            raise Exception(f"执行命令时发生错误：{str(e)}")

    def get_who(self):
        # 获取当前的链接对象
        output = self.execute_command('who')
        return output

    def get_ip_address(self):
        # 获取主机的 IP 地址。
        # 会返回当前主机上所有可用网络接口的 IP 地址，每个 IP 地址之间以空格分隔。
        output = self.execute_command("hostname -I")
        return output.strip()

    def get_system_info(self):
        # 主机名称
        hostname = self.execute_command("hostname").strip()
        # 发行版本和内核版本
        release_info = self.execute_command('cat /etc/*-release')
        release_info = release_info.split('\n')[0]
        kernel_version = self.execute_command("uname -r").strip()
        # 系统类型
        system_type = self.execute_command("uname -m").strip()
        # 启动时间
        boot_time = self.execute_command("who -b").strip().split(' ')[-2:]
        boot_time = ' '.join(boot_time)
        # 运行时间
        uptime = self.execute_command("uptime").split(',')
        uptime = uptime[0].strip().split(' ')[-1]

        # 构建系统信息字典
        system_info = {
            'hostname': hostname,
            'release_info': release_info,
            'kernel_version': kernel_version,
            'system_type': system_type,
            'boot_time': boot_time,
            'uptime': uptime,
        }
        return system_info

    def get_cpu_usage(self):
        # 获取CPU使用率
        output = self.execute_command("top -bn1 | grep 'Cpu(s)' | awk '{print $2 + $4}'")
        return float(output)

    def get_cpu_details(self):
        res = self.execute_command('lscpu')

    def get_cpu_info(self):
        # 获取 CPU 相关信息并筛选出型号和频率
        cpu_model = self.execute_command("lscpu | grep 'Model name'")
        cpu_model = cpu_model.split('\n')[0].split(':')[1].strip()
        # 获取 CPU 相关信息并筛选出核心数量
        cpu_core_total = self.execute_command("lscpu | grep 'Core(s) per socket'")
        cpu_core_total = cpu_core_total.split('\n')[0].split(':')[1].strip()
        # 查看每个 CPU 插槽上的物理核心数
        cpu_physics_per = self.execute_command('grep "physical id" /proc/cpuinfo | sort -u | wc -l').strip()
        # 查看实时 CPU 使用率
        output = self.execute_command("top -bn1 | grep '%Cpu'")
        user_cpu_use, sys_cpu_use = [data.strip().split(' ')[0] for data in output.split(':')[-1].split(',')[0:2]]
        formatted_output = {
            'cpu_model': cpu_model,
            'cpu_core_total': cpu_core_total,
            'cpu_physics_per': cpu_physics_per,
            'user_cpu_use': user_cpu_use,
            'sys_cpu_use': sys_cpu_use,
        }

        return formatted_output

    def get_disk_usage(self):
        output = self.execute_command("df -h /")
        # 将文本按行拆分
        lines = output.split('\n')
        # 获取第二行的信息
        x, filesystem_size, used_space, available_space, usage_percent, mount_point = lines[1].split()
        # 格式化输出
        formatted_output = {
            'filesystem_size': filesystem_size,
            'used_space': used_space,
            'available_space': available_space,
            'usage_percent': usage_percent,
            'mount_point': mount_point,
        }

        return formatted_output

    # 获取 inode 的使用情况
    def get_inode_info(self):
        output = self.execute_command("df -i /")
        # 将文本按行拆分
        lines = output.split('\n')
        # 获取第二行的信息
        filesystem, inodes, iUsed, iFree, iUse, mount_point = lines[1].split()
        # 格式化输出
        # 格式化输出
        formatted_output = {
            'filesystem': filesystem,
            'inodes': inodes,
            'iUsed': iUsed,
            'iFree': iFree,
            'iUse': iUse,
            'mount_point': mount_point,
        }
        print(formatted_output)
        return formatted_output

    def get_disk_usage_detail(self):
        # 存放磁盘使用信息
        disk_info = []
        # 获取磁盘使用信息
        output = self.execute_command("df -h")
        # 跳过第一行标题
        lines = output.strip().split('\n')[1:]
        # 遍历磁盘使用情况
        for line in lines:
            # 使用空格或多个空格作为分隔符
            parts = re.split(r'\s+', line)
            # Filesystem Size  Used Avail Use% Mounted on  六个信息
            if len(parts) == 6:
                filesystem, size, used, avail, use_percent, mounted_on = parts
                # 构建磁盘信息字典
                disk_info.append({
                    'Filesystem': filesystem,
                    'Size': size,
                    'Used': used,
                    'Avail': avail,
                    'Use%': use_percent,
                    'Mounted on': mounted_on
                })
        # 磁盘信息
        print(disk_info)
        return disk_info

    def format_network_interfaces(self, interfaces_output):
        # 使用正则表达式提取网络接口信息
        pattern = re.compile(r"([a-zA-Z0-9]+):\s+flags=(\d+)<(.+)>")
        matches = pattern.findall(interfaces_output)

        formatted_interfaces = []
        for match in matches:
            interface_name = match[0]
            flags = match[1]
            extra_info = match[2]

            # 将提取的信息格式化为字典
            interface_info = {
                "InterfaceName": interface_name,
                "Flags": flags,
                "ExtraInfo": extra_info
            }
            formatted_interfaces.append(interface_info)

        return formatted_interfaces

    def get_memory_usage_formatted(self):
        # 获取内存使用情况
        memory_output = self.execute_command("free -h | grep Mem:")
        # 格式化处理内存使用情况
        # 使用正则表达式提取内存使用情况
        pattern = re.compile(
            r"Mem:\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)"
        )
        match = pattern.search(memory_output)
        if match:
            total_memory = match.group(1)
            used_memory = match.group(2)
            free_memory = match.group(3)
            shared_memory = match.group(4)
            buffer_memory = match.group(5)
            available_memory = match.group(6)
            return {
                "TotalMemory": total_memory,
                "UsedMemory": used_memory,
                "FreeMemory": free_memory,
                "SharedMemory": shared_memory,
                "BufferMemory": buffer_memory,
                "AvailableMemory": available_memory
            }
        else:
            return {}

    def get_network_interfaces_formatted(self):
        # 获取网络接口
        interfaces_output = self.execute_command("ifconfig -a")
        # 格式化处理网络接口信息
        formatted_interfaces = self.format_network_interfaces(interfaces_output)
        return formatted_interfaces

    def get_who_formatted(self):
        # 获取访问用户的IP地址
        who_output = self.execute_command("who")
        # 格式化处理用户登录信息
        # 按换行符分割输出，每行代表一个用户登录信息
        lines = who_output.strip().split('\n')

        formatted_output = []
        for line in lines:
            # 按空格拆分每行，提取相关信息
            parts = line.split()
            if len(parts) >= 5:
                username = parts[0]
                terminal = parts[1]
                date_time = f"{parts[2]} {parts[3]}"
                remote_ip = parts[4]

                # 将提取的信息格式化为字典
                user_info = {
                    "Username": username,
                    "Terminal": terminal,
                    "LoginDateTime": date_time,
                    "RemoteIP": remote_ip
                }
                formatted_output.append(user_info)

        return formatted_output

    def get_netstat_formatted(self):
        # 获取更详细的网络连接信息
        netstat_output = self.execute_command("netstat -tn")
        # 格式化处理网络连接信息
        # 使用正则表达式匹配需要的网络连接信息
        # 这个示例中，我们匹配了本地IP地址、本地端口、远程IP地址和远程端口
        pattern = re.compile(r"(\d+\.\d+\.\d+\.\d+):(\d+)\s+(\d+\.\d+\.\d+\.\d+):(\d+)")
        matches = pattern.findall(netstat_output)

        formatted_output = []
        if matches:
            for match in matches:
                local_ip, local_port, remote_ip, remote_port = match
                formatted_output.append({
                    "Local IP": local_ip,
                    "Local Port": local_port,
                    "Remote IP": remote_ip,
                    "Remote Port": remote_port
                })
        return formatted_output

    def get_now_ip(self):
        output = self.execute_command('netstat -t')
        return output

    def get_load_average(self):
        # 获取负载平均值
        output = self.execute_command("cat /proc/loadavg")
        # 拆分字符串，获取平均负载的三个值
        first, second, third = output.split()[:3]
        formatted_output = {
            'first': first,
            'second': second,
            'third': third,
        }
        return formatted_output

    def close(self):
        self.ssh_client.close()

    def connect_redis(self):
        # Redis连接信息
        redis_host = 'localhost'
        redis_port = 6379  # 默认Redis端口
        redis_db = 0

        # 创建Redis连接
        redis_client = redis.StrictRedis(host=redis_host, port=redis_port, db=redis_db)

        # 将服务器信息存储到Redis
        redis_client.set('ip_address', self.get_ip_address())
        # redis_client.set('hostname', self.get_hostname())
        redis_client.set('cpu_usage', self.get_cpu_usage())
        redis_client.set('load_average', self.get_load_average())

    def create_circle(self):
        cpu_usage = self.get_cpu_usage()
        CommonMatplot().create_circle(cpu_usage=cpu_usage, other=100 - cpu_usage)

    def _get_locations(self):
        title = 'CONTAINER ID   IMAGE                                     COMMAND                  CREATED        STATUS                 PORTS                                                                     NAMES'
        # 计算 CONTAINER ID 和 IMAGE 之间的距离
        a = title.find('IMAGE') - title.find('CONTAINER ID')
        # 计算 IMAGE 和 COMMAND 之间的距离
        b = title.find('COMMAND') - title.find('IMAGE')
        # 计算 COMMAND 和 CREATED 之间的距离
        c = title.find('CREATED') - title.find('COMMAND')
        # 计算 CREATED 和 STATUS 之间的距离
        d = title.find('STATUS') - title.find('CREATED')
        # 计算 STATUS 和 PORTS 之间的距离
        e = title.find('PORTS') - title.find('STATUS')
        # 计算 PORTS 和 NAMES 之间的距离
        f = title.find('NAMES') - title.find('PORTS')
        # 计算NAMES的位置
        g = title.find('NAMES')
        return a, b, c, d, e, f, g

    def _perform_docker_containers(self, container_data):
        container_dict = {}
        a, b, c, d, e, f, g = self._get_locations()
        container_id = container_data[0:a - 3]
        container_image = container_data[a:a + b - 3]
        container_command = container_data[a + b:a + b + c - 3]
        container_created = container_data[a + b + c:a + b + c + d - 3]
        container_status = container_data[a + b + c + d:a + b + c + d + e - 3]
        container_port = container_data[a + b + c + d + e:a + b + c + d + e + f - 3]
        container_name = container_data[g:]

        container_dict['container_id'] = container_id
        container_dict['container_image'] = container_image
        container_dict['container_command'] = container_command
        container_dict['container_created'] = container_created
        container_dict['container_status'] = container_status
        container_dict['container_port'] = container_port
        container_dict['container_name'] = container_name
        return container_dict

    def get_docker_data(self):
        output = self.execute_command('docker ps')
        container_list = output.split('\n')
        container_dict_data = []
        for info in range(0, len(container_list) - 1):
            if info == 0:
                continue
            else:
                container_data = container_list[info]
                container_dict = self._perform_docker_containers(container_data)
                container_dict_data.append(container_dict)

        return container_dict_data


# 示例用法：
if __name__ == "__main__":
    monitor = RemoteServerMonitor()
    # {'hostname': 'VM-8-11-opencloudos',
    # 'release_info': '',
    # 'kernel_version': '5.4.119-20.0009.21.spr',
    # 'system_type': 'x86_64',
    # 'boot_time': '2023-10-09 13:00',
    # 'uptime': '5:06'}
    kernel_version = monitor.get_system_info()
    # kernel_version = monitor.execute_command('cat /etc/*-release')
    # kernel_version = kernel_version.split('\n')[0]
    print(kernel_version)
